/** @file         xxx_driver.c
 *  @brief        驱动文件
 *  @details      基于驱动模块的方式实现 驱动注册/注销等等操作。
 *  @author       lzm
 *  @date         2021-03-21 10:22:03
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/


#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>

/* 
 * 步骤注释声明
 * [module]：模块框架
 * [bus_dev]：总线设备框架。
 * [bus_drv]：总线驱动框架。
 * 总线设备框架和总线驱动框架都是属于内核的架子，和模块框架一个性质。 
 */

/* [bus_drv][1] */
/* 声明外部总线 */
extern struct bus_type lzm_bus;

/* [bus_drv][2] */
/* 实现驱动结构体内容 */
/** @brief  xxx_drv_probe 匹配成功后的回调函数
  * @param  
  * @retval
  * @author lzm
  */
int xxx_drv_probe(struct device *dev)
{
    printk("%s-%s\n", __FILE__, __func__); // 打印文件名及函数
}

/** @brief  xxx_drv_remove 删除驱动时执行的回调函数
  * @param  
  * @retval
  * @author lzm
  */
int xxx_drv_remove(struct device *dev)
{
    printk("%s-%s\n", __FILE__, __func__); // 打印文件名及函数
}

/* [bus_drv][3] */
/* 填充驱动结构体 */
static struct device_driver xxx_drv =
{
	.name = "xxx_dev", // 名字必须和设备结构体 .init_name 一致，用于匹配。
	.bus = &lzm_bus,
  .probe = xxx_drv_probe,
  .remove = xxx_drv_remove,
};

/* [bus_drv][4] */
/* 实现属性文件所需内容 */
static char *drv_name = "xxx_bus";
/* 注：_show 和 _store 函数的前缀就是属性文件名称。（两函数前缀必须保持一致） */
/* 实现 show 回调函数，让用户能通过 cat 命令获取该驱动信息 */
/** @brief  drv_attr_show 属性文件名称为 drv_attr
  * @param  
  * @retval 
  * @author lzm
  */
ssize_t drv_attr_show(struct device_driver *drv, char *buf)
{
    return sprintf(buf, "%s\n", drv_name); // 拷贝到 buf 中
}
DRIVER_ATTR_RO(drv_attr); // 只读文件 drv_attr。DRIVER_ATTR_WO   DRIVER_ATTR_RW



/* [module][1] */
/** @brief   xxx_drv_init
  * @details drv module 入口函数
  * @param  
  * @retval 
  * @author lzm
  */
static int __init xxx_drv_init(void)
{
    printk("xxx_drv init!\n");
    
    /* [bus_drv][5] 注册驱动 */
    driver_register(&xxx_drv);

    /* [bus_drv][6] 创建属性文件*/
    driver_create_file(&xxx_drv, &driver_attr_drv_attr); // 创建后会在 /sys/bus/<bus-name>/drivers/<driver-name> 下出现。

    return 1;
}
module_init(xxx_drv_init);

/* [module][2] */
/** @brief   xxx_drv_exit
  * @details drv module 出口函数
  * @param  
  * @retval 
  * @author lzm
  */
static void __exit xxx_drv_exit(void)
{
    printk("xxx_drv exit!\n");

    /* [bus_drv][7] 删除属性文件 */
    driver_remove_file(&xxx_drv, &driver_attr_drv_attr);

    /* [bus_drv][8] 注销驱动 */
    driver_unregister(&xxx_drv);
}
module_exit(xxx_drv_exit);

/* [module][3] */
MODULE_AUTHOR("lizhuming");
MODULE_LICENSE("GPL");

